﻿[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Additions.CompareConstraint.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Additions.CompareConstraint.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.ScriptResource("BM.Tools.WebControls.MForm.Controls.Additions.CompareConstraint.js", "BM.Tools.WebControls.MForm.Resources.CompareConstraintResource", "BM.CompareConstraintResource")]

namespace BM.Tools.WebControls.MForm.Controls.Additions
{
    using System;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Globalization;
    using System.Text.RegularExpressions;
    using System.Web.Script.Serialization;
    using System.Web.UI.WebControls;

    using AjaxControlToolkit;
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;    

    /// <summary>
    /// A compare constraint that can be created on the item.
    /// Very similiar to the <see cref="CompareValidator"/> but works with the MForm item controls validation.
    /// </summary>
    [ClientScriptResource("BM.Tools.WebControls.MForm",
            "BM.Tools.WebControls.MForm.Controls.Additions.CompareConstraint.js")]
    public class CompareConstraint : Constraint
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CompareConstraint"/> class. 
        /// </summary>
        public CompareConstraint()
        {
            Type = ValidationDataType.String;
            Operator = ValidationCompareOperator.Equal;
        }

        /// <summary>
        /// Gets or sets the data type of the comparison validation
        /// </summary>
        [AttributeProperty(Name = "type")]
        [DefaultValue(ValidationDataType.String)]
        public ValidationDataType Type
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the type of the comparison operator
        /// </summary>
        [AttributeProperty(Name = "operator")]
        [DefaultValue(ValidationCompareOperator.Equal)]
        public ValidationCompareOperator Operator
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the compare parameters that are used by the javascript compare function.
        /// </summary>
        [AttributeProperty(Name = "compareParameters")]
        [TypeConverter(typeof(NameValueCollectionJsonConverter))]
        public NameValueCollection CompareParameters
        {
            get
            {
                var compareParameters = new NameValueCollection();
                var numberFormat = CultureInfo.CurrentCulture.NumberFormat;
                switch (Type)
                {
                    case ValidationDataType.Date:
                        var dateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
                        compareParameters.Add("cutoffyear", dateTimeFormat.Calendar.TwoDigitYearMax.ToString());
                        compareParameters.Add("dateorder", DummyCompareValidator.GetDateElementOrder());
                        break;
                    case ValidationDataType.Currency:
                        compareParameters.Add("decimalchar", numberFormat.CurrencyDecimalSeparator);
                        compareParameters.Add("groupchar", numberFormat.CurrencyGroupSeparator);
                        compareParameters.Add("digits", numberFormat.CurrencyDecimalDigits.ToString());
                        compareParameters.Add("groupsize", numberFormat.CurrencyGroupSizes[0].ToString());
                        break;
                    case ValidationDataType.Double:
                        compareParameters.Add("decimalchar", numberFormat.NumberDecimalSeparator);
                        break;
                }

                return compareParameters;
            }
        }

        /// <summary>
        /// Gets or sets the fixed value that the item is compared to.
        /// </summary>
        [AttributeProperty(Name = "valueToCompare")]
        public string ValueToCompare
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the xpath-like path to the comparison item.
        /// </summary>
        [AttributeProperty(Name = "itemToComparePath")]
        public string ItemToComparePath
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the comparison item based on the <see cref="ItemToComparePath"/>.
        /// </summary>
        public LeafItem ItemToCompare
        {
            get
            {
                return Owner.SelectSingle(ItemToComparePath) as LeafItem;
            }
        }

        /// <summary>
        /// Gets the default error text.
        /// </summary>
        protected override string DefaultErrorText
        {
            get
            {
                return string.Format("{0} {1} '{2}'.", Resources.CompareConstraintResource.CompareConstraintError, Resources.CompareConstraintResource.ResourceManager.GetString("Not_" + Operator), ToCompare);
            }
        }

        /// <summary>
        /// Gets the serializer that will serialize addition metadata.
        /// </summary>
        protected override JavaScriptSerializer JsonSerializer
        {
            get
            {
                var serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new JavaScriptConverter[] { new CompareConstraintJavaScriptConverter(), new NameValueCollectionJsonConverter() });
                return serializer;
            }
        }

        private string ToCompare
        {
            get
            {
                return !string.IsNullOrEmpty(ItemToComparePath) ? ItemToCompare.Value : ValueToCompare;
            }
        }

        /// <summary>
        /// Checks the validity of the item
        /// </summary>
        /// <param name="item">
        /// The checked item.
        /// </param>
        /// <returns>
        /// is the constraint met for the item
        /// </returns>
        public override bool IsValid(OffspringItem item)
        {
            var leafItem = item as LeafItem;
            var value = (leafItem != null) ? leafItem.Value : null;
            if (value == null || value.Trim().Length == 0)
            {
                return true;
            }

            if (!IsInStandardDateFormat(value))
            {
                value = ConvertToShortDateString(value);
            }

            var toCompare = ToCompare;
            if (toCompare == null || toCompare.Trim().Length == 0)
            {
                return true;
            }

            if (!IsInStandardDateFormat(toCompare))
            {
                toCompare = ConvertToShortDateString(toCompare);
            }

            return DummyCompareValidator.Compare(value, toCompare, Operator, Type);
        }

        private static bool IsInStandardDateFormat(string date)
        {
            return Regex.Match(date, @"^\s*(\d+)([-/]|\. ?)(\d+)\2(\d+)\s*$").Success;
        }

        private static string ConvertToShortDateString(string text)
        {
            DateTime dateTime;
            if (DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out dateTime))
            {
                text = dateTime.ToShortDateString();
            }

            return text;
        }
    }
}
